package cn.lingyangwl.agile.auth.third;

import cn.binarywang.wx.miniapp.api.WxMaService;
import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult;
import cn.binarywang.wx.miniapp.bean.WxMaPhoneNumberInfo;
import cn.lingyangwl.agile.auth.constants.CacheKeyEnum;
import cn.lingyangwl.agile.auth.model.ThirdBindContent;
import cn.lingyangwl.agile.auth.model.rqrs.third.*;
import cn.lingyangwl.agile.dynamic.client.AbstractClientProcess;
import cn.lingyangwl.agile.dynamic.client.wx.WxMaWrapClient;
import cn.lingyangwl.agile.model.constants.ValidationCons;
import cn.lingyangwl.agile.model.enums.ConfigDefineEnum;
import cn.lingyangwl.agile.model.module.auth.GrantTypeEnum;
import cn.lingyangwl.framework.tool.core.StringUtils;
import cn.lingyangwl.framework.tool.core.exception.Assert;
import cn.lingyangwl.framework.tool.core.exception.BizException;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.error.WxErrorException;
import org.springframework.stereotype.Component;

/**
 * 微信小程序授权登录
 *
 * @author shenguangyang
 */
@Slf4j
@Component
public class WxMaAuth extends BaseThirdAuth {

    interface Keys {
        String CODE = "code";
    }

    @Override
    public GrantTypeEnum grantType() {
        return GrantTypeEnum.WEIXIN_MA;
    }

    @Override
    public ThirdUserInfoResp getUserInfo(ThirdUserGetReq req) {
        String phoneCode = req.getPhoneCode();
        Assert.notEmpty(phoneCode, "手机号code" + ValidationCons.NOT_EMPTY);

        ThirdUserInfoResp resp = new ThirdUserInfoResp();

        try {
            WxMaWrapClient dynamicClient = (WxMaWrapClient) AbstractClientProcess.getDynamicClient(ConfigDefineEnum.WX_MA);
            WxMaPhoneNumberInfo phoneNoInfo = dynamicClient.getWxMaService().getUserService().getPhoneNoInfo(phoneCode);
            resp.setPhone(phoneNoInfo.getPhoneNumber());

            // 将用户信息存入到缓存中
            /*
             * 第三方用户信息, 比如微信小程序在授权时候主动获取手机号, 会通过微信小程序颁发的phoneCode获取手机号, 且只能
             * 获取一次, 为了后续绑定使用, 需要保存一下
             */
            CacheKeyEnum keyEnum = CacheKeyEnum.THIRD_USER_INFO;
            String cacheKey = keyEnum.formatKey(phoneCode);
            redisTemplate.opsForValue().set(cacheKey, resp.getPhone(), keyEnum.getExpire(), keyEnum.getUnit());
            resp.setCode(phoneCode);
            return resp;
        } catch (Exception e) {
            log.error("error: ", e);
            throw new BizException("获取用户手机号失败");
        }
    }

    /**
     * 因为采用小程序一键获取手机号绑定, 所以不需要校验验证码
     */
    @Override
    protected void bindVerify(ThirdBindContent content) {

    }

    @Override
    protected void fillBindUserInfo(ThirdBindContent content) {
        Assert.notEmpty(content.getPhoneCode(), "手机号code" + ValidationCons.NOT_EMPTY);
        String phoneCode = content.getPhoneCode();
        // 先从缓存中获取, 获取不到再调用微信小程序获取手机号
        CacheKeyEnum keyEnum = CacheKeyEnum.THIRD_USER_INFO;
        String phone = (String) redisTemplate.opsForValue().get(keyEnum.formatKey(phoneCode));

        if (StringUtils.isEmpty(phone)) {
            try {
                WxMaWrapClient dynamicClient = (WxMaWrapClient) AbstractClientProcess.getDynamicClient(ConfigDefineEnum.WX_MA);
                WxMaPhoneNumberInfo phoneNoInfo = dynamicClient.getWxMaService().getUserService().getPhoneNoInfo(phoneCode);
                phone = phoneNoInfo.getPhoneNumber();
            } catch (Exception e) {
                log.error("error: {}", e.getMessage());
                throw new BizException("获取手机号失败/已过期, 请重新授权登录");
            }
        }
        content.setAccount(phone);
    }

    @Override
    public ThirdAuthUser doLogin(ThirdLoginReq req) {
        Assert.notEmpty(req.getCode(), Keys.CODE + ValidationCons.NOT_EMPTY);

        try {
            WxMaWrapClient dynamicClient = (WxMaWrapClient) AbstractClientProcess.getDynamicClient(ConfigDefineEnum.WX_MA);
            WxMaService maService = dynamicClient.getWxMaService();
            WxMaJscode2SessionResult sessionInfo = maService.getUserService().getSessionInfo(req.getCode());

            ThirdAuthUser thirdAuthUser = new ThirdAuthUser();
            thirdAuthUser.setOpenId(sessionInfo.getOpenid());
            thirdAuthUser.setRedirectUrl("");
            thirdAuthUser.setIsRedirect(false);
            return thirdAuthUser;
        } catch (BizException e) {
            throw e;
        } catch (Exception e) {
            if (e instanceof WxErrorException) {
                throw new BizException(((WxErrorException) e).getError().getErrorMsg());
            }
            log.error("error: ", e);
            throw new BizException("授权失败");
        }
    }

    @Override
    public ThirdAuthResp doAuthorize(AuthUrlGetReq req) {
        throw new BizException("小程序无需获取授权地址");
    }
}
